/*
	       File: frmMain.cs
	Create Date: 2007-09-22
	    Version:

	Description:


	 Change log:


*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace GuerillaProgrammer.FileProcessor.ServiceMonitor
{
    public partial class frmMain : Form
    {
        #region Private member fields
        [DllImport("advapi32.dll")]
        private static extern IntPtr OpenSCManager(string lpMachineName, string lpSCDB, int scParameter);
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern IntPtr CreateService(IntPtr hSCManager, string lpServiceName, string lpDisplayName, uint dwDesiredAccess, uint dwServiceType, uint dwStartType, uint dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, uint lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword);
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
        [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool DeleteService(IntPtr hService);
        [DllImport("advapi32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool StartService(IntPtr hService, int dwNumServiceArgs, string[] lpServiceArgVectors);
        [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool ControlService(IntPtr hService, SERVICE_CONTROL dwControl, ref SERVICE_STATUS lpServiceStatus);
        [DllImport("advapi32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseServiceHandle(IntPtr hSCObject);

        private const int SC_MANAGER_CREATE_SERVICE = 0x0002;
        private const int STANDARD_RIGHTS_REQUIRED = (0x000F0000);
        private const int SERVICE_QUERY_CONFIG = 0x0001;
        private const int SERVICE_CHANGE_CONFIG = 0x0002;
        private const int SERVICE_QUERY_STATUS = 0x0004;
        private const int SERVICE_ENUMERATE_DEPENDENTS = 0x0008;
        private const int SERVICE_START = 0x0010;
        private const int SERVICE_STOP = 0x0020;
        private const int SERVICE_PAUSE_CONTINUE = 0x0040;
        private const int SERVICE_INTERROGATE = 0x0080;
        private const int SERVICE_USER_DEFINED_CONTROL = 0x0100;
        private const int SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL);
        private const int SERVICE_WIN32_OWN_PROCESS = 0x00000010;
        private const int SERVICE_AUTO_START = 0x00000002;
        private const int SERVICE_ERROR_NORMAL = 0x00000001;

        [StructLayout(LayoutKind.Sequential)]
        private struct SERVICE_STATUS
        {
            public int serviceType;
            public int currentState;
            public int controlsAccepted;
            public int win32ExitCode;
            public int serviceSpecificExitCode;
            public int checkPoint;
            public int waitHint;
        }

        [Flags]
        public enum SERVICE_CONTROL : uint
        {
            STOP = 0x00000001,
            PAUSE = 0x00000002,
            CONTINUE = 0x00000003,
            INTERROGATE = 0x00000004,
            SHUTDOWN = 0x00000005,
            PARAMCHANGE = 0x00000006,
            NETBINDADD = 0x00000007,
            NETBINDREMOVE = 0x00000008,
            NETBINDENABLE = 0x00000009,
            NETBINDDISABLE = 0x0000000A,
            DEVICEEVENT = 0x0000000B,
            HARDWAREPROFILECHANGE = 0x0000000C,
            POWEREVENT = 0x0000000D,
            SESSIONCHANGE = 0x0000000E
        }
        public enum SERVICE_STATE : uint
        {
            SERVICE_STOPPED = 0x00000001,
            SERVICE_START_PENDING = 0x00000002,
            SERVICE_STOP_PENDING = 0x00000003,
            SERVICE_RUNNING = 0x00000004,
            SERVICE_CONTINUE_PENDING = 0x00000005,
            SERVICE_PAUSE_PENDING = 0x00000006,
            SERVICE_PAUSED = 0x00000007
        }
        [Flags]
        public enum SERVICE_ACCEPT : uint
        {
            STOP = 0x00000001,
            PAUSE_CONTINUE = 0x00000002,
            SHUTDOWN = 0x00000004,
            PARAMCHANGE = 0x00000008,
            NETBINDCHANGE = 0x00000010,
            HARDWAREPROFILECHANGE = 0x00000020,
            POWEREVENT = 0x00000040,
            SESSIONCHANGE = 0x00000080,
        }
        [Flags]
        public enum SCM_ACCESS : uint
        {
            STANDARD_RIGHTS_REQUIRED = 0xF0000,
            SC_MANAGER_CONNECT = 0x00001,
            SC_MANAGER_CREATE_SERVICE = 0x00002,
            SC_MANAGER_ENUMERATE_SERVICE = 0x00004,
            SC_MANAGER_LOCK = 0x00008,
            SC_MANAGER_QUERY_LOCK_STATUS = 0x00010,
            SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020,
            SC_MANAGER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
                SC_MANAGER_CONNECT |
                SC_MANAGER_CREATE_SERVICE |
                SC_MANAGER_ENUMERATE_SERVICE |
                SC_MANAGER_LOCK |
                SC_MANAGER_QUERY_LOCK_STATUS |
                SC_MANAGER_MODIFY_BOOT_CONFIG
        }
        #endregion

        #region Constructors and cleanup methods
        public frmMain()
        {
            InitializeComponent();
            GetServiceStatus();
            txtPath.Text = @"C:\program files\engine of progress\grinder\";
        }
        #endregion

        #region Private implementation methods
        private IntPtr GetSCM()
        {
            IntPtr scm = IntPtr.Zero;
            IntPtr newServiceHandle = IntPtr.Zero;
            //uint groupID = 0;
            scm = OpenSCManager(null, null, SC_MANAGER_CREATE_SERVICE);
            if (IntPtr.Zero == scm)
            {
                //we failed!
                int error = Marshal.GetLastWin32Error();
                MessageBox.Show(string.Format("Error getting SCM!\nError: {0}", error), "Error getting SCM!");
                return IntPtr.Zero;
            }

            return scm;              
        }
        private IntPtr GetFileProcessor(IntPtr scm)
        {
            IntPtr schFileProcessor = OpenService(scm, "Grinder", SERVICE_ALL_ACCESS);
            if (IntPtr.Zero == schFileProcessor)
            {
                int error = Marshal.GetLastWin32Error();
                MessageBox.Show(string.Format("Error getting SCM!\nError: {0}", error), "Error getting SCM!");
                return IntPtr.Zero;
            }
            return schFileProcessor;
        }
        private void GetServiceStatus()
        {
            IntPtr scm = GetSCM();
            if (IntPtr.Zero != scm)
            {
                SERVICE_STATUS svcStat = new SERVICE_STATUS();
                IntPtr schFileProc = GetFileProcessor(scm);
                if (IntPtr.Zero == schFileProc)
                {
                    return;
                }

                if (true == ControlService(schFileProc, SERVICE_CONTROL.INTERROGATE, ref svcStat))
                {
                    //int svcStatus = svcStat.currentState;
                    switch (svcStat.currentState)
                    {
                        case (int) SERVICE_STATE.SERVICE_RUNNING:
                            txtStatus.Text = "RUNNING";
                            break;
                        case (int) SERVICE_STATE.SERVICE_STOPPED:
                            txtStatus.Text = "STOPPED";
                            break;
                        case (int) SERVICE_STATE.SERVICE_PAUSED:
                            txtStatus.Text = "PAUSED";
                            break;
                        default:
                            txtStatus.Text = "huh?";
                            break;
                    }
                }
                else
                {
                    txtStatus.Text = "Can't determine (probably not running)";
                }
            }

        }
        #endregion

        #region Class properties
        #endregion

        #region Events handlers
        private void btnExit_Click(object sender, EventArgs e)
        {
            Close();
        }
        private void btnInstall_Click(object sender, EventArgs e)
        {
            //First get the username & password to use
            frmUserID userID = new frmUserID();
            string username;
            string password;
            if (DialogResult.OK == userID.ShowDialog())
            {
                username = userID.UserName;
                password = userID.Password;
            }
            else
            {
                MessageBox.Show("Cannot install the service without a user id");
                return;
            }

            IntPtr scm = GetSCM();
            if (IntPtr.Zero == scm)
            {
                return;
            }

            string currentPath = Path.Combine(txtPath.Text, "FileProcessorService.exe");
            uint groupID = 0;
            IntPtr newServiceHandle = CreateService(scm, "Grinder", "Grinder", SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, currentPath, null, groupID, null, username, password);
            if (IntPtr.Zero == newServiceHandle)
            {
                int error = Marshal.GetLastWin32Error();
                return;
            }

            return;
        }
        private void btnUninstall_Click(object sender, EventArgs e)
        {
            IntPtr scm = GetSCM();
            if (IntPtr.Zero == scm)
            {
                return;
            }

            IntPtr schService = OpenService(scm, "Grinder", SERVICE_ALL_ACCESS);
            if (IntPtr.Zero != schService)
            {
                if (true == DeleteService(schService))
                {
                    MessageBox.Show("Service has been deleted", "Delete Service");
                }
                else
                {
                    MessageBox.Show(string.Format("Could not delete service!\nError: {0}", Marshal.GetLastWin32Error()), "Service not deleted");
                }
                CloseServiceHandle(schService);
            }
            CloseServiceHandle(scm);
        }
        private void btnStart_Click(object sender, EventArgs e)
        {
            IntPtr scm = GetSCM();
            if (IntPtr.Zero == scm)
            {
                return;
            }

            IntPtr schFileProcessor = OpenService(scm, "Grinder", SERVICE_ALL_ACCESS);
            if (IntPtr.Zero != schFileProcessor)
            {
                if (true == StartService(schFileProcessor, 0, null))
                {
                    MessageBox.Show("Service started.");
                    GetServiceStatus();
                }
                else
                {
                    MessageBox.Show(string.Format("Failed to start service.\nError: {0}",Marshal.GetLastWin32Error()));
                    GetServiceStatus();
                }
                CloseServiceHandle(schFileProcessor);
            }
            CloseServiceHandle(scm);
        }
        private void btnStop_Click(object sender, EventArgs e)
        {
            IntPtr scm = GetSCM();
            if (IntPtr.Zero == scm)
            {
                return;
            }

            IntPtr schFileProcessor = GetFileProcessor(scm);
            if (IntPtr.Zero != schFileProcessor)
            {
                SERVICE_STATUS svcStatus = new SERVICE_STATUS();
                if (true == ControlService(schFileProcessor, SERVICE_CONTROL.STOP, ref svcStatus))
                {
                    MessageBox.Show("The service has stopped.", "Stop Service");
                    GetServiceStatus();
                }
                else
                {
                    MessageBox.Show(string.Format("Failed to stop service.\nError: {0}", Marshal.GetLastWin32Error()), "Error!");
                    GetServiceStatus();
                }
            }
            CloseServiceHandle(schFileProcessor);
            CloseServiceHandle(scm);
        }
        private void btnRefresh_Click(object sender, EventArgs e)
        {
            GetServiceStatus();
        }
        #endregion

        #region Public interface
        #endregion
    }
}